const fs = require('fs')
const path = require('path')
const { Worker } = require('worker_threads')
const os = require('os')

// 私有化包列表
const storagePlugin_list = [
  'verdaccio-custom',
  'CetVirtualTree',
  '@omega/admin',
  '@omega/app',
  '@omega/auth',
  '@omega/cli',
  '@omega/cli-codestd',
  '@omega/cli-devops',
  '@omega/cli-devserver',
  '@omega/dashboard',
  '@omega/fusion',
  '@omega/http',
  '@omega/i18n',
  '@omega/icon',
  '@omega/map',
  '@omega/schedule',
  '@omega/theme',
  '@omega/trend',
  '@omega/usercenter',
  '@omega/video',
  '@omega/virtualtree',
  '@omega/weather',
  '@omega/widget',
  'cet-chart',
  'cet-common',
  'cet-echarts-extend-map',
  'cet-eem-common',
  'cet-eem-common-test',
  'cet-eem-oilgasfield-common',
  'cet-graph',
  'cet-realtime',
  'cet-smart-water-material',
  'cet-task',
  'cet-video',
  'cet-waveform',
  'cettreeV2',
  '@omega/eslint-plugin',
  'lowcode-common',
  'fusion-manage',
  '@omega/eslint-config',
  '@omega/tsconfig',
  '@omega/utils',
  '@omega/vite-plugin-devserver',
  '@omega/chart',
  '@omega/core',
  'fusion-api',
  'fusion-subapp-vue3',
  'fusion-subapp',
  '@omega/layout',
  'pq-commonweb-package',
  '@omega/unity3d',
  'vue-project-package-split',
  '@omega/tracking',
  '@altair/lord',
  '@altair/knight',
  'cet-pq-common',
  '@altair/blade',
  '@omega/scalescreen',
  '@powercloud/common',
  '@altair/pack'
]

// 日志文件路径
const logFilePath = 'E:\\CET2025\\verdaccio\\logs\\3th-verdaccio-out.log'
// const logFilePath = 'E:\\CET2025\\verdaccio\\logs\\verdaccio copy.log'
// const logFilePath = 'C:\\Users\\Administrator\\AppData\\Roaming\\verdaccio\\logs\\verdaccio.log'

// 将日志文件拆分为多个部分
function splitLogFile(logFilePath, numWorkers) {
  const fileSize = fs.statSync(logFilePath).size
  const num = fileSize < 1000000000 ? 1 : numWorkers
  const chunkSize = Math.ceil(fileSize / num)
  const chunks = []

  for (let i = 0; i < numWorkers; i++) {
    const start = i * chunkSize
    const end = (i + 1) * chunkSize
    chunks.push({ start, end })
  }

  return chunks
}

function getTimeRange() {
  // 获取本周的时间范围
  const now = new Date()

  // 本日 Today
  const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())
  const startTimestamp = startOfDay.getTime()

  const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1)
  endOfDay.setMilliseconds(-1)
  const endTimestamp = endOfDay.getTime()

  // 最近七天
  const lastWeek = Date.now() - 7 * 24 * 60 * 60 * 1000

  // 最近一个月
  const lastMonth = new Date()
  lastMonth.setMonth(lastMonth.getMonth() - 1)

  // 获取本周的第一天（周一）
  const startOfWeek = new Date(now)
  startOfWeek.setDate(now.getDate() - now.getDay() + 1)
  startOfWeek.setHours(0, 0, 0, 0)

  // 获取本周的最后一天（周日）
  const endOfWeek = new Date(now)
  endOfWeek.setDate(now.getDate() - now.getDay() + 7)
  endOfWeek.setHours(23, 59, 59, 999)

  // 获取本月的时间范围
  // 获取本月的第一天
  const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
  startOfMonth.setHours(0, 0, 0, 0)

  // 获取本月的最后一天
  const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0)
  endOfMonth.setHours(23, 59, 59, 999)

  return {
    dayTime: [startTimestamp, endTimestamp],
    agoTime: [lastWeek, new Date(lastMonth).getTime()],
    weekTime: [new Date(startOfWeek).getTime(), new Date(endOfWeek).getTime()],
    monthTime: [new Date(startOfMonth).getTime(), new Date(endOfMonth).getTime()]
  }
}

// 启动 Worker 线程
function startWorkers(logFilePath, chunks) {
  const timeRange = getTimeRange()

  return new Promise((resolve, reject) => {
    const workers = []
    const results = []
    let completedWorkers = 0

    chunks.forEach((chunk, index) => {
      const workerPath = path.resolve(__dirname, 'worker.js')
      const worker = new Worker(workerPath, {
        workerData: {
          isPm2Hosting: true,
          logFilePath,
          start: chunk.start,
          end: chunk.end,
          timeRange
        }
      })

      worker.on('message', (result) => {
        results[index] = result
        completedWorkers++

        // 所有 Worker 线程完成后，合并结果
        if (completedWorkers === chunks.length) {
          const mergedResult = mergeResults(results)
          const packageStats = calculatePackageStats(mergedResult)

          resolve(packageStats)

          // 将结果导出为 JSON 文件
          fs.writeFileSync(path.join(__dirname, 'download_stats_results.json'), JSON.stringify(mergedResult, null, 2))
          fs.writeFileSync(path.join(__dirname, 'download_stats_total.json'), JSON.stringify(packageStats, null, 2))
          // fs.writeFileSync(path.join(__dirname, 'download_stats_week.json'), JSON.stringify(mergedResult.lastWeek, null, 2))

          if (timer) {
            console.log('所有 Worker 线程已完成, 读取日志文件成功')
            clearInterval(timer)
            timer = null
          }
        }
      })

      worker.on('error', (error) => {
        console.error(`Worker ${index} 出错:`, error)
        reject(`Worker ${index} 出错:`, error)
      })

      worker.on('exit', (code) => {
        if (code !== 0) {
          console.error(`Worker ${index} 退出，代码: ${code}`)
          reject(`Worker ${index} 退出，代码: ${code}`)
        }
      })

      workers.push(worker)
    })
  })
}

const filterData = (data, result = {}) => {
  Object.entries(data).forEach(([packageName, count]) => {
    const name = decodeURIComponent(packageName)

    storagePlugin_list.forEach((pkg) => {
      if (name === pkg || (name.includes(pkg) && name.endsWith('.tgz'))) {
        result[name] = (result[name] || 0) + count
      }
    })
  })
  return result
}

// 合并 Worker 线程的结果
function mergeResults(results) {
  const downloadStats = {}
  const lastWeek = {}
  const thisWeek = {}
  const lastMonth = {}
  const thisMonth = {}

  results.forEach((result) => {
    filterData(result.downloadStats, downloadStats)
    filterData(result.lastWeek, lastWeek)
    filterData(result.thisWeek, thisWeek)
    filterData(result.lastMonth, lastMonth)
    filterData(result.thisMonth, thisMonth)
  })

  return {
    downloadStats,
    lastWeek,
    thisWeek,
    lastMonth,
    thisMonth
  }
}

let timer = null
let number = 0

// 主函数
const main = async () => {
  // 获取 CPU 核心数
  const cpuCount = os.cpus().length
  console.log(`当前电脑 CPU ${cpuCount} 核, 即将启动多线程读取日志文件`)

  timer = setInterval(() => {
    number++
    console.log(`${number}`)
  }, 1000)

  const chunks = splitLogFile(logFilePath, cpuCount)
  const res = await startWorkers(logFilePath, chunks)
}

// 计算包下载量统计
function calculatePackageStats(logs) {
  const packageTotal = []
  const packageDetail = {}
  const lastWeekLogs = []
  const lastMonthLogs = []
  const thisWeekLogs = []
  const thisMonthLogs = []

  storagePlugin_list.forEach((pkg) => {
    let totalDownloads = 0
    let totalWeekDownloads = 0
    let totalMonthDownloads = 0
    let totalthisWeekDownloads = 0
    let totalthisMonthDownloads = 0

    packageDetail[pkg] = {
      total: 0,
      details: []
    }
    const pattern = `${pkg}/-/.*.tgz`
    const regex = new RegExp(pattern)

    for (const key in logs.downloadStats) {
      if (logs.downloadStats.hasOwnProperty(key)) {
        if (key === pkg || regex.test(key)) {
          totalDownloads += logs.downloadStats[key]
          packageDetail[pkg].details.push({
            packageName: key,
            version: key,
            value: logs.downloadStats[key],
            weekDownloads: logs.lastWeek[key] || 0,
            monthDownloads: logs.lastMonth[key] || 0,
            thisWeekDownloads: logs.thisWeek[key] || 0,
            thisMonthDownloads: logs.thisMonth[key] || 0
          })
        }
      }
    }

    for (const key in logs.lastWeek) {
      if (logs.lastWeek.hasOwnProperty(key)) {
        if (key === pkg || regex.test(key)) {
          totalWeekDownloads += logs.lastWeek[key]
          const index = lastWeekLogs.findIndex((item) => item.packageName === key)
          if (index !== -1) return

          lastWeekLogs.push({
            packageName: key,
            value: logs.lastWeek[key] || 0
          })
        }
      }
    }

    for (const key in logs.lastMonth) {
      if (logs.lastMonth.hasOwnProperty(key)) {
        if (key === pkg || regex.test(key)) {
          totalMonthDownloads += logs.lastMonth[key]
          const index = lastMonthLogs.findIndex((item) => item.packageName === key)
          if (index !== -1) return

          lastMonthLogs.push({
            packageName: key,
            value: logs.lastMonth[key] || 0
          })
        }
      }
    }

    for (const key in logs.thisWeek) {
      if (logs.thisWeek.hasOwnProperty(key)) {
        if (key === pkg || regex.test(key)) {
          totalthisWeekDownloads += logs.thisWeek[key]
          const index = thisWeekLogs.findIndex((item) => item.packageName === key)
          if (index !== -1) return

          thisWeekLogs.push({
            packageName: key,
            value: logs.thisWeek[key] || 0
          })
        }
      }
    }

    for (const key in logs.thisMonth) {
      if (logs.thisMonth.hasOwnProperty(key)) {
        if (key === pkg || regex.test(key)) {
          totalthisMonthDownloads += logs.thisMonth[key]
          const index = thisMonthLogs.findIndex((item) => item.packageName === key)
          if (index !== -1) return

          thisMonthLogs.push({
            packageName: key,
            value: logs.thisMonth[key] || 0
          })
        }
      }
    }

    packageDetail[pkg].total = totalDownloads
    packageTotal.push({
      packageName: pkg,
      version: '',
      value: totalDownloads,
      totalWeekDownloads,
      totalMonthDownloads,
      totalthisWeekDownloads,
      totalthisMonthDownloads,
      details: packageDetail[pkg].details
    })
  })

  return {
    downloadLogs: packageTotal,
    config: this.config,
    tableList: {
      lastWeekLogs: lastWeekLogs.sort((a, b) => b.value - a.value),
      lastMonthLogs: lastMonthLogs.sort((a, b) => b.value - a.value),
      thisWeekLogs: thisWeekLogs.sort((a, b) => b.value - a.value),
      thisMonthLogs: thisMonthLogs.sort((a, b) => b.value - a.value)
    }
  }
}

main()
